public class AddressValidator {
    
    static final StrikeIronInfo__c info = [select userid__c,password__c from strikeironinfo__c where active__c = true limit 1];
    
  //Future annotation to mark the method as async.
  @Future(callout=true) 
  public static void validateAddress(String id) {
    String msg = '';
    try {
        Candidate__c cand = [select AsyncValidationFlag__c, Street_Address_1__c, Street_Address_2__c, city__c, state_Province__c, zip_postal_code__c, country__c, valid_us_address__c, county__c, congress_district__c, latitude__c, longitude__c, address_error__c from candidate__c where id=:id];                                        
        msg += 'candidate=' + cand + '\n\n';
        msg += 'info=' + info + '\n\n';
        
        //construct an HTTP request
        HttpRequest req = new HttpRequest();
        String endpoint = 'http://ws.strikeiron.com/StrikeIron/USAddressVerification4_0/USAddressVerification/VerifyAddressUSA?';
        String uId = 'LicenseInfo.RegisteredUser.UserID=' + EncodingUtil.urlEncode(info.userid__c,'UTF-8');
        String pw = '&LicenseInfo.RegisteredUser.Password=' + info.password__c;
        String street1 = '&VerifyAddressUSA.addressLine1=';
        street1 += cand.Street_Address_1__c != null ? EncodingUtil.urlEncode(cand.Street_Address_1__c,'UTF-8') : '';
        String street2 = '&VerifyAddressUSA.addressLine2=';
        street2 += cand.Street_Address_2__c != null ?  EncodingUtil.urlEncode(cand.Street_Address_2__c,'UTF-8') : '';
        String citystatezip = '&VerifyAddressUSA.city_state_zip=';
        citystatezip += cand.City__c != null ? EncodingUtil.urlEncode(cand.City__c + ' ','UTF-8') : '';
        citystatezip += cand.State_Province__c != null ?  EncodingUtil.urlEncode(cand.State_Province__c + ' ','UTF-8') : '';
        citystatezip += cand.Zip_Postal_Code__c != null ? EncodingUtil.urlEncode(cand.Zip_Postal_Code__c,'UTF-8') : '';
        
        // now combine all the params into one string (named endpoint)
        endpoint += uId + pw + street1 + street2 + citystatezip + '&VerifyAddressUSA.casing=Proper';
        
        msg += 'endpoint=' + endpoint + '\n';
        req.setEndpoint(endpoint);
        req.setMethod('GET');
    
        //send the request
        Http http = new Http();
    
        HttpResponse res = http.send(req);
        if (res.getStatusCode() == 200) {
          //update candidate
          
          // now let's actually do something useful with the response
          XMLDom doc = new XMLDom(res.getBody());
          
          // get the main part of the address results out of the xml response
          XMLDom.Element result = doc.getElementByTagName('VerifyAddressUSAResult');
          
          // find out if the address is valid
          if (result.getValue('AddressStatus') == 'Valid'){
            // let's update the Candidate address info with the Country, Zip+4, County, CongressDistrict, and Lat & Long
            cand.valid_us_address__c = true;
            cand.Country__c = 'US';
            cand.Zip_Postal_Code__c = result.getValue('ZipPlus4');
            cand.County__c = result.getValue('County');
            cand.Congress_District__c = result.getValue('CongressDistrict');
            cand.Latitude__c = Double.valueOf(result.getValue('Latitude'));
            cand.Longitude__c = Double.valueOf(result.getValue('Longitude'));
            cand.address_error__c = '';
          } else {
            cand.County__c = '';
            cand.Congress_District__c = '';
            cand.Latitude__c = null;
            cand.Longitude__c = null;
            cand.address_error__c = result.getValue('AddressErrorNumber') + ' - '  +result.getValue('AddressErrorMessage');
            cand.valid_us_address__c = false;
          }
          cand.asyncvalidationflag__c = true;
          msg += 'async updated candidate=' + cand + '\n';
          update cand;
        } else {
          System.debug('Callout failed: ' + res);
          msg += 'STATUS:'+res.getStatus();
          msg += '\nSTATUS_CODE:'+res.getStatusCode();
          msg += '\nBODY: '+res.getBody();
          Error_Log__c log = new Error_Log__c();
          log.trace__c = msg;
          insert log;
        } 
        
    } catch(Exception e) {
        System.debug('ERROR: '+ e);
        Error_Log__c log = new Error_Log__c();
        log.trace__c = msg + '\n' + e.getCause() + '\n' + e.getMessage();
        insert log;
    }
  }
  
}